<template>
  <div id="blocker" style="width:100%;height: 100%;position: relative">
    <div style="width:100%;height: 100%;display: block;overflow-x: hidden;overflow-y: hidden;"
         id="container">
    </div>
    <button @click="generateBox" style="position: absolute;right: 0px;top: 0px">生成</button>
  </div>
</template>

<script type="module">
import * as THREE from 'three'
import Editor from './js/Editor'
import { FBXLoader } from 'three/examples/jsm/loaders/FBXLoader'
import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader'
import { TransformControls } from 'three/examples/jsm/controls/TransformControls'

const ThreeBSP = require('three-js-csg')(THREE)

let container, editor
let renders

let pointer, raycaster, isShiftDown = false
//红色方块mesh
let rollOverMesh, rollOverMaterial
const objects = []
let tempLine = null//线
let point1 = new THREE.Vector3()
let point2 = new THREE.Vector3()
//保存每点击两次的坐标
let feature = []
//点击次数
let cnt = 0
let color = ''

function coordinates () {
  this.point_1 = new THREE.Vector3()
  this.point_2 = new THREE.Vector3()
}

export default {
  name: 'THREETest',
  data () {
    return {
      fileUrl: config.url.file.fileUrl,
    }
  },
  props: ['msg'],
  components: {},
  mounted () {

  },
  methods: {
    adds (url) {
      window.addEventListener('resize', this.onWindowResize, false)//屏幕适应监听
      window.addEventListener('click', this.onWindowResize, false)//屏幕适应监听

      window.addEventListener('pointermove', this.onPointerMove)
      window.addEventListener('click', this.onPointerDown)
      window.addEventListener('keydown', this.onDocumentKeyDown)
      window.addEventListener('keyup', this.onDocumentKeyUp)

      const that = this
      container = document.getElementById('container')
      editor = new Editor(container, url)
      editor.scene.renderer.domElement.style.outline = 'none'
      container.appendChild(editor.scene.renderer.domElement)
      that.animate()

      editor.model.loadModel()
      let modelLoadInterval = setInterval(() => {
        if (editor.model) {
          clearInterval(modelLoadInterval)
        }
      }, 100)
      that.initModel()
      that.initScenario()
    },
    //生成几何体
    generateBox () {
      for (let i = 0; i < feature.length; i++) {
        console.log(feature[i])
        this.drawLineBox(feature[i].point_1, feature[i].point_2, 150)
      }
    },
    //
    drawLineBox (start, end, height) {
      var d = this.createCylinderByTwoPoints(start, end, height)
      editor.scene.scene.add(d)
    },
    //根据两个坐标，生成几何体
    createCylinderByTwoPoints (vstart, vend, vheight) {
      var HALF_PI = Math.PI * .5

      //vstart坐标到vend坐标的间距
      var distance = vstart.distanceTo(vend)  //短一点的立方体
      var position = vend.clone().add(vstart).divideScalar(2)

      var material = new THREE.MeshLambertMaterial({
        color: 0x0000ff
      })
      var cylinder = new THREE.BoxGeometry(50, distance + 50, vheight)

      var orientation = new THREE.Matrix4()
      var offsetRotation = new THREE.Matrix4()
      var offsetPosition = new THREE.Matrix4()
      orientation.lookAt(vstart, vend, new THREE.Vector3(0, 5, 0))
      offsetRotation.makeRotationX(HALF_PI)
      orientation.multiply(offsetRotation)
      cylinder.applyMatrix(orientation)

      var mesh = new THREE.Mesh(cylinder, material)
      mesh.position.set(position.x, vheight / 2, position.z)
      return mesh
    },
    //初始化
    initScenario () {
      //创建一个地板，如果只有网格，不能那到点击位置的坐标
      let geometry = new THREE.PlaneGeometry(1000, 1000)
      geometry.rotateX(-Math.PI / 2)
      let mail = new THREE.MeshBasicMaterial({ visible: true })
      let plane = new THREE.Mesh(geometry, mail)
      editor.scene.scene.add(plane)
      objects.push(plane)

      //射线
      raycaster = new THREE.Raycaster()

      //红色方块
      const rollOverGeo = new THREE.PlaneBufferGeometry(50, 50)
      rollOverMaterial = new THREE.MeshLambertMaterial({
        color: 0xff0000,
        opacity: 0.5,
        transparent: true,
      })
      rollOverMesh = new THREE.Mesh(rollOverGeo, rollOverMaterial)
      rollOverMesh.rotateX(-Math.PI / 2)
      rollOverMesh.position.y = -10
      editor.scene.scene.add(rollOverMesh)

      //网格
      var gridHelper = new THREE.GridHelper(1000, 20)
      // editor.scene.scene.add(gridHelper)

      //鼠标的二维坐标，在归一化的设备坐标(NDC)中，也就是X 和 Y 分量应该介于 -1 和 1 之间。
      pointer = new THREE.Vector2()

    },
    qwe(){
      console.log(editor.scene.scene)
      const cubeGeometry = new THREE.BoxGeometry(30, 39, 20)
      const cube = this.createMesh(cubeGeometry)
      for(let i=0;i<editor.scene.scene.children.length;i++){
        if(editor.scene.scene.children[i].name=="qwe"){
          const sphereBSP = new ThreeBSP(editor.scene.scene.children[i])
          const cubeBSP = new ThreeBSP(cube)
          const resultBSP = sphereBSP.subtract(cubeBSP)
          const result = resultBSP.toMesh()

          result.geometry.computeFaceNormals()

          result.geometry.computeVertexNormals()
          cube.position.x = -50

          const material = new THREE.MeshPhongMaterial({ color: 0x00ffff })

          result.material = material
          result.position.y=30

          editor.scene.scene.add(result)
          editor.scene.scene.remove(editor.scene.scene.children[i])
        }
      }
    },
    initModel () {

      const sphereGeometry = new THREE.BoxGeometry(100, 40, 20)
      const sphere = this.createMesh(sphereGeometry)

      sphere.name='qwe'
      editor.scene.scene.add(sphere)

      // const sphereGeometry = new THREE.BoxGeometry(100, 40, 20)
      // const sphere = this.createMesh(sphereGeometry)
      //
      // const cubeGeometry = new THREE.BoxGeometry(30, 39, 20)
      // const cube = this.createMesh(cubeGeometry)
      // cube.position.y = 20
      //
      // const sphereBSP = new ThreeBSP(sphere)
      // const cubeBSP = new ThreeBSP(cube)
      //
      // const resultBSP = sphereBSP.subtract(cubeBSP)
      // const result = resultBSP.toMesh()
      //
      // result.geometry.computeFaceNormals()
      //
      // result.geometry.computeVertexNormals()
      // cube.position.x = -50
      //
      // const material = new THREE.MeshPhongMaterial({ color: 0x00ffff })
      //
      // result.material = material
      //
      // editor.scene.scene.add(result)

      // new FBXLoader().load("http://localhost:3000/file/getFile/cs1/model/jun.FBX",fbx=>{
      //   editor.scene.scene.add(fbx)
      // })
    },
    createMesh (geom) {
      //  创建一个线框纹理
      const wireFrameMat = new THREE.MeshBasicMaterial({
        opacity: 0.5,
        wireframeLinewidth: 0.5,
        color:0x70dbdb
      })
      //wireFrameMat.wireframe = true

      // 创建模型
      const mesh = new THREE.Mesh(geom, wireFrameMat)

      return mesh
    },
    //滑动执行
    onPointerMove (event) {

      if (this.msg == '1') {
        color = 0x70dbdb
      } else if (this.msg == '2') {
        color = 0xd71345
      } else if (this.msg == '3') {
        color = 0x70dbdb
      } else {
        color = 0x70dbdb
      }

      //ray因为屏幕有侧边栏，位置偏移问题
      let getBoundingClientRect = container.getBoundingClientRect()
      pointer.set(((event.clientX - getBoundingClientRect.left) / container.offsetWidth) * 2 - 1, -((event.clientY - getBoundingClientRect.top) / container.offsetHeight) * 2 + 1)
      raycaster.setFromCamera(pointer, editor.scene.camera)
      const intersects = raycaster.intersectObjects(objects)

      if (intersects.length > 0) {
        const intersect = intersects[0]
        rollOverMesh.position.copy(intersect.point).add(intersect.face.normal)
        // rollOverMesh.position.divideScalar(50).floor().multiplyScalar(50).addScalar(25)

        point2.copy(intersect.point).add(intersect.face.normal)
        point2.divideScalar(1).floor().multiplyScalar(1).addScalar(1)
        point2.y = 0

        if (cnt == 1) {
          if (tempLine) {
            editor.scene.scene.remove(tempLine)
          }
          var geometry = new THREE.Geometry()
          geometry.vertices.push(point1)
          geometry.vertices.push(point2)
          tempLine = new THREE.Line(geometry, new THREE.LineDashedMaterial({
            color: color,
            scale: 0.1
          }))
          tempLine.computeLineDistances()
          editor.scene.scene.add(tempLine)
        }

      }
      this.render()
    },
    //点击执行
    onPointerDown (event) {
      console.log(this.msg)

      //ray因为屏幕有侧边栏，位置偏移问题
      let getBoundingClientRect = container.getBoundingClientRect()
      pointer.set(((event.clientX - getBoundingClientRect.left) / container.offsetWidth) * 2 - 1, -((event.clientY - getBoundingClientRect.top) / container.offsetHeight) * 2 + 1)
      raycaster.setFromCamera(pointer, editor.scene.camera)

      if (tempLine && cnt == 1) {
        editor.scene.scene.remove(tempLine)
      }
      const intersects = raycaster.intersectObjects(objects)
      console.log(intersects)
      if (intersects.length > 0) {
        const intersect = intersects[0]
        if (event.button == 0) {
          if (isShiftDown) {
            if (intersect.object !== plane) {
              editor.scene.scene.remove(intersect.object)
              objects.splice(objects.indexOf(intersect.object), 1)
            }

          } else {
            //点击位置生成预制几何体
            // const voxel = new THREE.Mesh(cubeGeo, cubeMaterial)
            // voxel.position.copy(intersect.point).add(intersect.face.normal)
            // voxel.position.divideScalar(50).floor().multiplyScalar(50).addScalar(25)
            // editor.scene.scene.add(voxel)
            // objects.push(voxel)

            switch (cnt) {
              case 0:
                point1.copy(intersect.point).add(intersect.face.normal)
                // point1.divideScalar(50).floor().multiplyScalar(50).addScalar(25)
                point1.y = 0
                break
              case 1:
                point2.copy(intersect.point).add(intersect.face.normal)
                // point2.divideScalar(50).floor().multiplyScalar(50).addScalar(25)
                point2.y = 0

                var geometry = new THREE.Geometry()
                geometry.vertices.push(point1)
                geometry.vertices.push(point2)
                var line = new THREE.Line(geometry, new THREE.LineDashedMaterial({
                  color: color,
                }))
                line.computeLineDistances()
                editor.scene.scene.add(line)
                objects.push(line)

                var a = new coordinates()
                a.point_1.copy(point1)
                a.point_2.copy(point2)
                a.sorts = 0
                feature.push(a)
                break

            }
            cnt = (cnt + 1) % 2
          }
          this.render()
        }
      }
    },
    onDocumentKeyDown (event) {
      switch (event.keyCode) {
        case 16:
          isShiftDown = true
          break

      }

    },
    onDocumentKeyUp (event) {

      switch (event.keyCode) {

        case 16:
          isShiftDown = false
          break

      }

    },
    render () {
      editor.scene.renderer.render(editor.scene.scene, editor.scene.camera)
    },
    animate () {
      let that = this
      renders = requestAnimationFrame(that.animate) //请求再次执行渲染函数render
      editor.scene.renderer.render(editor.scene.scene, editor.scene.camera)//执行渲染操作
    },
    //屏幕适应
    onWindowResize () {
      editor.scene.camera.aspect = container.clientWidth / container.clientHeight
      editor.scene.camera.updateProjectionMatrix()
      editor.scene.renderer.setSize(container.clientWidth, container.clientHeight)
    },
    //删除模型
    initDispose () {
      let that = this
      if (editor.scene.scene) {
        let allChildren = editor.scene.scene.children.filter(x => x)
        allChildren.forEach(a => {
          that.dispose(editor.scene.scene, a)
        })
        editor.scene.scene.dispose()
        editor.scene.scene.remove()
        editor.scene.renderer.dispose()
        editor.scene.renderer.forceContextLoss()
        editor.scene.renderer.content = null
        editor.scene.renderer.domElement = null
        cancelAnimationFrame(renders)
      }

    },
    dispose (parent, child) {
      if (child.children.length) {
        let arr = child.children.filter(x => x)
        arr.forEach(obj => {
          this.dispose(child, obj)
        })
      }
      if (child.type === 'Mesh' || child.type === 'Line') {
        if (child.material.map) {
          if (child.material.map.dispose) {
            child.material.map.dispose()
          }
        }
        if (child.material.dispose) {
          child.material.dispose()
        }
        if (child.geometry.dispose) {
          child.geometry.dispose()
        }
      } else if (child.material) {
        if (child.material.dispose) {
          child.material.dispose()
        }
      }
      child.remove()
      parent.remove(child)
    },
  },
  destroyed () {
    this.initDispose()
  },
}
</script>
<style scoped>
</style>
